<template>
  <div class="paper-list">
    <!-- <div class="panel-header">
      <div class="header-content">
        <h1 class="panel-title">试卷</h1>
        <p class="panel-subtitle">创建和管理您的考试内容</p>
      </div>
      <div>
        
      </div>
    </div> -->
    <div>
      <!-- <el-button type="primary" @click="openDialog">导入 .paper 试卷</el-button> -->
      <input
        type="file"
        ref="fileInput"
        style="display: none"
        accept=".paper"
        @change="handleFileChange"
      />
      <el-dialog
        title="请填写导入后的试卷名称，请勿重复！"
        :visible.sync="dialogVisible"
        :close-on-click-modal="false"
        width="30%"
      >
        <el-input v-model="customPaperName" placeholder="试卷名称" />
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleDialogConfirm"
            >确定</el-button
          >
        </span>
      </el-dialog>
    </div>
    <div v-if="loading" class="loading-state">
      <div class="spinner"></div>
      <p class="">加载中...</p>
    </div>

    <div v-else class="papers-grid">
      <router-view />

      <!-- 用于检测触底的标记元素 - 始终渲染但可能不可见 -->
      <div
        ref="observerTarget"
        class="loading-indicator"
        :style="{ display: noMore ? 'none' : 'flex' }"
      >
        <div class="spinner"></div>
        <p class="end-of-list">加载更多内容...</p>
      </div>

      <!--      <p v-if="noMore" style="text-align: center; padding: 1rem; color: #6B7280;">
        <i class="fa fa-check-circle mr-1"></i>已加载全部内容
      </p>-->
    </div>

    <div :class="{ 'AIPaperGeneratorModal-class': getGenerateModelStatus }">
      <AIPaperGeneratorModal
        v-if="getGenerateModelStatus"
        @close="closeGeneratorModal"
      ></AIPaperGeneratorModal>
    </div>
  </div>
</template>

<script>
import PaperEditorModal from "../components/paper/PaperEditorModal.vue";
import AIPaperGeneratorModal from "@/components/paper/AIPaperGeneratorModal.vue";
import { mapGetters } from "vuex";
import {
  listPapers as listPapersAPI,
  getPaperQuestions as getPaperQuestionsAPI,
} from "@/api/paper/index";
import axios from "axios";

import { getBaseURL } from '@/assets/js/config'; // 引入获取基础URL的函数

export default {
  name: "PaperList",
  components: {
    PaperEditorModal,
    AIPaperGeneratorModal,
  },
  data() {
    return {
      editorMode: "create",
      currentUserId: 2,
      showAIPaperGenerator: false,
      dialogVisible: false,
      customPaperName: "",
      observer: null, // Intersection Observer实例
      loadingMore: false, // 加载更多状态
      scrollListener: null, // 滚动监听函数引用
      observerInitAttempts: 0, // 初始化尝试次数
      maxInitAttempts: 5, // 最大尝试次数
      initAttemptInterval: 500, // 尝试间隔(ms)
      isFirstLoad: true, // 标记首次加载
    };
  },
  computed: {
    ...mapGetters("paper", [
      "getPapers",
      "getLoading",
      "getCheckedPaper",
      "getGeneratePaperId",
      "getGenerateModelStatus",
      "getPaperQuestions",
      "getListParam",
      "getTotal",
    ]),
    ...mapGetters("user", ["getUserInfo"]),
    // 计算属性映射
    total: {
      get() {
        return this.getTotal;
      },
      set(v) {
        this.$store.commit("paper/setTotal", v);
      },
    },
    listParam: {
      get() {
        return this.getListParam;
      },
      set(v) {
        this.$store.commit("paper/setListParam", v);
      },
    },
    generateModelStatus: {
      get() {
        return this.getGenerateModelStatus;
      },
      set(v) {
        this.$store.commit("paper/setGenerateModelStatus", v);
      },
    },
    checkedPaper: {
      get() {
        return this.getCheckedPaper;
      },
      set(v) {
        this.$store.commit("paper/setCheckedPaper", v);
      },
    },
    papers: {
      get() {
        return this.getPapers;
      },
      set(v) {
        this.$store.commit("paper/setPapers", v);
      },
    },
    loading: {
      get() {
        return this.getLoading;
      },
      set(v) {
        this.$store.commit("paper/setLoading", v);
      },
    },
    generatePaperId: {
      get() {
        return this.getGeneratePaperId;
      },
      set(v) {
        this.$store.commit("paper/setGeneratePaperId", v);
      },
    },
    paperQuestions: {
      get() {
        return this.getPaperQuestions;
      },
      set(v) {
        this.$store.commit("paper/setPaperQuestions", v);
      },
    },
    // 搜索过滤
    filteredPapers() {
      if (!this.searchQuery) return this.papers;
      return this.papers.filter((paper) =>
        paper.paper_name.toLowerCase().includes(this.searchQuery.toLowerCase())
      );
    },

    // 触底加载状态
    noMore() {
      return this.papers.length >= this.total || this.loadingMore; // 加载中时不触发再次加载
    },
    disabled() {
      return this.loadingMore || this.noMore;
    },
  },
  created() {
    this.fetchPapers();
    this.$registerWebSocketHandler(this.handleMessage);
    if (this.$route.query.path === "generator") {
      this.fetchPapers();
    }
  },
  activated() {
    // 组件被激活时调用(使用keep-alive时)
    this.refreshData();
  },
  // 修改 mounted 钩子
  mounted() {
    // **关键：使用 $nextTick 确保 DOM 渲染完成后再初始化**
    this.$nextTick(() => {
      this.tryInitIntersectionObserver();
    });

    // 监听 papers 和 total 变化，但仅在初始化失败时重试
    this.$watch(
      () => ({ papers: this.papers, total: this.total }),
      () => {
        if (
          !this.observer &&
          this.observerInitAttempts < this.maxInitAttempts
        ) {
          this.tryInitIntersectionObserver();
        }
      },
      { deep: true }
    );
  },

  // 修改 tryInitIntersectionObserver
  tryInitIntersectionObserver() {
    if (this.observer || this.observerInitAttempts >= this.maxInitAttempts) {
      return;
    }

    this.observerInitAttempts++;

    // **关键：直接检查元素是否存在，避免多次延迟尝试**
    if (this.$refs.observerTarget) {
      this.initIntersectionObserver();
    } else {
      // 超过最大尝试次数后，回退到滚动监听
      if (this.observerInitAttempts >= this.maxInitAttempts) {
        this.initScrollListener();
      }
    }
  },
  beforeRouteEnter(to, from, next) {
    // 在路由进入前重置数据
    next((vm) => {
      vm.resetListParams();
      vm.refreshData();
    });
  },
  beforeDestroy() {
    this.$unregisterWebSocketHandler(this.handleMessage);

    // 清理资源
    if (this.observer) {
      this.observer.disconnect();
      this.observer = null;
    }

    if (this.scrollListener) {
      window.removeEventListener("scroll", this.scrollListener);
      this.scrollListener = null;
    }
  },
  methods: {
    // 重置列表参数
    resetListParams() {
      this.listParam.pageNum = 1;
      this.papers = [];
      this.total = 0;
      this.loadingMore = false;
    },

    // 刷新数据
    refreshData() {
      this.resetListParams();
      this.fetchPapers();
    },
    // 尝试初始化Intersection Observer
    tryInitIntersectionObserver() {
      // 如果已经初始化或达到最大尝试次数则返回
      if (this.observer || this.observerInitAttempts >= this.maxInitAttempts) {
        return;
      }

      this.observerInitAttempts++;

      // 使用nextTick确保DOM更新
      this.$nextTick(() => {
        if (this.$refs.observerTarget) {
          this.initIntersectionObserver();
        } else {
          setTimeout(
            () => this.tryInitIntersectionObserver(),
            this.initAttemptInterval
          );
        }
      });
    },

    // 初始化Intersection Observer
    initIntersectionObserver() {
      if (!this.$refs.observerTarget) {
        console.warn(
          "observerTarget元素不存在，无法初始化Intersection Observer"
        );
        return;
      }

      if ("IntersectionObserver" in window) {
        this.observer = new IntersectionObserver(
          (entries) => {
            entries.forEach((entry) => {
              if (entry.isIntersecting && !this.disabled) {
                this.loadMoreContent();
              }
            });
          },
          {
            root: null,
            rootMargin: "0px 0px 200px 0px",
            threshold: 0.1,
          }
        );

        this.observer.observe(this.$refs.observerTarget);
      } else {
        // 回退到传统滚动监听
        this.scrollListener = () => {
          if (this.disabled) return;

          const scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop;
          const scrollHeight =
            document.documentElement.scrollHeight || document.body.scrollHeight;
          const clientHeight =
            document.documentElement.clientHeight || window.innerHeight;

          if (scrollTop + clientHeight >= scrollHeight - 200) {
            this.loadMoreContent();
          }
        };

        window.addEventListener("scroll", this.scrollListener);
      }
    },

    // 加载更多内容
    async loadMoreContent() {
      // 防止重复触发或无更多数据
      if (this.loadingMore || this.noMore) return;

      // 计算总页数
      const pageSize = this.listParam.pageSize;
      const totalPages = Math.ceil(this.total / pageSize);
      const nextPage = this.listParam.pageNum + 1;

      // 若下一页超过总页数，终止加载
      if (nextPage > totalPages) {
        return;
      }

      // 更新页码并请求数据
      this.listParam.pageNum = nextPage;

      this.loadingMore = true;

      try {
        const res = await listPapersAPI(this.listParam);
        const { data } = res.data;

        // 校验服务器响应
        /*if (data.pageNum !== nextPage) {
          throw new Error(`服务器返回页码错误：期望 ${nextPage}，实际 ${data.pageNum}`);
        }
        if (!Array.isArray(data.rows)) {
          throw new Error('服务器返回数据格式错误，rows 缺失或非数组');
        }*/

        // 去重逻辑
        const existingIds = new Set(this.papers.map((paper) => paper.paperId));
        const newPapers = data.rows.filter(
          (paper) => !existingIds.has(paper.paperId)
        );

        //刷新页面
        if (newPapers.length === 0) {
          this.refreshData();
        }
        // 更新数据
        this.papers = [...this.papers, ...newPapers];
        this.total = data.total; // 确保总条数与服务器一致

      } catch (error) {
        this.$message.error("数据加载失败，请重试");
        // 错误时回退页码
        this.listParam.pageNum = Math.max(1, this.listParam.pageNum - 1);
      } finally {
        this.loadingMore = false;
      }
    },
    // 处理websocket发送来的消息的方法
    handleMessage(message) {
      // console.log("当前页面处理消息：", message);
      if (message.messageType == 1) {
        this.fetchPapers();
      } else if (message.messageType == 2) {
        // 打开编辑框
        this.editPaper({ paperId: message.content });
      } else if (message.messageType == 3) {
        // 创建试卷时触发
        this.generatePaperId = message.content;
        this.paperGenerator();
      } else if (message.messageType == 4) {
        this.listParam.paperName = message.content;
        this.listParam.pageNum = 1;
        this.fetchPapers();
      } else if (message.messageType == 5) {
        // 处理试卷中添加的题目
        let newQuestions = JSON.parse(message.content);
        // 将数据添加进入vuex中
        this.$store.commit("paper/setPaperQuestions", newQuestions);
      } else if (message.messageType == 6) {
        // 导出word
        let res = JSON.parse(message.content);
        this.exportWord(res);
      } else if (message.messageType == 7) {
        // 导出excel
        this.exportExcel(message.content);
      } else if (message.messageType == 8) {
        // 切换到题库页面
        this.$router.push("/question-bank");
      } else if (message.messageType == 9) {
        // 导出试卷为paper文件
        let res = JSON.parse(message.content);
        this.$export.exportToPaper(res.data, res.paperName);
        this.$message.success("导出试卷成功！");
      } else if (message.messageType == 10) {
        // 回到首页
        this.generatePaperId = null;
        this.paperQuestions = [];
        this.fetchPapers();
        this.$router.push("/paper-index");
      } else if (message.messageType == 11) {
        // 打开导入弹窗
        this.openDialog();
      }
      // 根据 message 内容做对应处理
    },
    // 导出 Word
    async exportWord(params) {
      let paperId = params.paperId;

      let targetPaper = this.papers.find((paper) => paper.paperId === paperId);
      try {
        const res = await getPaperQuestionsAPI({ paperId: paperId });
        const { data } = res.data;

        // 导出 Word 的逻辑
        this.$export.exportPaperToWordV2(
          data,
          {
            paperName: targetPaper.paperName,
            creator: this.getUserInfo.realName,
            duration: targetPaper.timeLimit,
          },
          params.isAnswer // 是否包含答案
        );
        this.$message.success("导出试卷成功！");
      } catch (error) {
        // console.error('导出 Word 失败:', error);
        this.$message.error("导出 Word 失败，请稍后重试");
        return;
      }
    },
    // 导出 Excel
    async exportExcel(paperId) {
      let targetPaper = this.papers.find(
        (paper) => paper.paperId === Number(paperId)
      );
      try {
        // 导出 Excel 的逻辑
        const res = await getPaperQuestionsAPI({ paperId: paperId });
        const { data } = res.data;

        const exportData = data.map((item, index) => ({
          序号: index + 1,
          题目名称: item.question ? item.question.content : "",
          类型: item.question
            ? this.getQuestionTypeText(item.question.type)
            : "",
          选项: item.question ? item.question.options : "",
          正确答案: item.question ? item.question.correctAnswer : "",
          解析: item.question ? item.question.parse : "",
          难度: item.question ? item.question.difficulty : "",
          分值: item.score,
        }));

        const filename = `${targetPaper.paperName || "试卷"}.xlsx`;
        this.$export.exportToExcel(exportData, filename);
        this.$message.success("导出试卷成功！");
      } catch (error) {
        this.$message.error("导出 Excel 失败，请稍后重试");
        return;
      }
    },

    // 用户点击按钮：打开输入框
    openDialog() {
      this.customPaperName = "";
      this.dialogVisible = true;
    },

    // 用户点击“确定”：先关闭弹窗，再触发文件选择
    handleDialogConfirm() {
      if (!this.customPaperName) {
        this.$message.warning("请填写导入后的试卷名称，请勿重复！");
        return;
      }

      this.dialogVisible = false;

      // 弹出文件选择
      this.$refs.fileInput.click();
    },

    // 文件选择完毕后：用 axios 上传文件
    async handleFileChange(event) {
      const file = event.target.files[0];

      if (!file || !file.name.endsWith(".paper")) {
        this.$message.error("请上传 .paper 格式的文件！");
        return;
      }

      const formData = new FormData();
      formData.append("file", file);
      formData.append("paperName", this.customPaperName);

      try {
        const response = await axios.post(
          `${getBaseURL()}/user/paper/import-paper`,
          formData,
          {
            headers: {
              Authorization: localStorage.getItem("token") || "",
              "Content-Type": "multipart/form-data",
            },
          }
        );

        const res = response.data;

        if (res.code === 200) {
          this.$message.success(res.message || "上传成功！");
          // 刷新试卷列表，并清空试卷名称
          this.customPaperName = "";
          this.fetchPapers?.();
        } else {
          this.$message.error(res.message || "上传失败！");
        }
      } catch (error) {
        console.error(error);
        this.$message.error("上传出错，请检查网络或服务器状态！");
      }

      // 清除 input 值，允许上传同一个文件多次
      event.target.value = "";
    },
    
    // 获取题型文本
    getQuestionTypeText(type) {
      const types = {
        0: "单选题",
        1: "多选题",
        2: "填空题",
        3: "判断题",
        4: "简答题",
      };
      return types[type] || "未知题型";
    },
    async fetchPapers() {
      this.loading = true;
      this.listParam.pageNum = 1;
      try {
        let res = await listPapersAPI(this.listParam);

        let { data } = res.data;

        this.papers = data.rows;
        this.total = data.total;
      } catch (error) {
        // console.error('获取试卷数据失败:', error);
        // this.$message.error('获取试卷数据失败，请稍后重试');
      } finally {
        this.loading = false;
      }
    },
    getCreatorName(userId) {
      const user = this.users.find((u) => u.id === userId);
      return user ? user.name : "未知";
    },
    getDifficultyText(level) {
      const levels = ["非常容易", "容易", "中等", "较难", "困难", "非常困难"];
      return levels[level - 1] || "未知";
    },
    formatDate(dateString) {
      const date = new Date(dateString);
      return `${date.getFullYear()}-${(date.getMonth() + 1)
        .toString()
        .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
    },
    handleSearch() {
      // 搜索逻辑已在计算属性中处理
    },
    closeGeneratorModal() {
      this.generateModelStatus = false;
      this.paperQuestions = [];
      this.generatePaperId = null;
      this.listParam.pageNum = 1;
      this.fetchPapers();
    },
    editPaper(paper) {
      this.$router.push("/paper-index/editor");
      this.checkedPaper = paper;
    },
    handleSavePaper(paper) {
      if (this.editorMode === "create") {
        const newPaper = {
          ...paper,
          paperId: Math.max(...this.papers.map((p) => p.paperId)) + 1,
          userId: this.currentUserId,
          createdAt: new Date().toISOString(),
          updatedAt: new Date().toISOString(),
        };
        this.papers.unshift(newPaper);
      } else {
        const index = this.papers.findIndex((p) => p.paperId === paper.paperId);
        if (index !== -1) {
          this.papers.splice(index, 1, {
            ...this.papers[index],
            ...paper,
            updatedAt: new Date().toISOString(),
          });
        }
      }
      this.showEditor = false;
    },
    togglePublish(paper) {
      const newStatus = paper.status === 1 ? 0 : 1;
      const index = this.papers.findIndex((p) => p.paperId === paper.paperId);
      if (index !== -1) {
        this.papers.splice(index, 1, {
          ...this.papers[index],
          status: newStatus,
          updatedAt: new Date().toISOString(),
        });
      }
    },
    paperGenerator() {
      this.$router.push("/paper-index/generator");
    },
    load() {
      // 这里可以添加加载更多试卷的逻辑
      // 例如，调用 API 获取更多试卷数据
      let paperLength =
        this.papers.length == "undefined" ? this.papers.length : 10;

      if (paperLength >= this.total) {
        return;
      }

      this.loadinging = true;
      this.listParam.pageNum += 1;

      setTimeout(async () => {
        try {
          let res = await listPapersAPI(this.listParam);
          let { data } = res.data;
          this.papers.push(...data.rows); // 拼接
        } catch (error) {
          // console.error('获取试卷数据失败:', error);
          this.$message.error("获取试卷数据失败，请稍后重试");
        } finally {
          this.loadinging = false;
        }
      }, 2000);
    },
    // ✅ 上传前校验，只允许 .paper 文件
    beforeUpload(file) {
      const isPaper = file.name.endsWith(".paper");
      if (!isPaper) {
        this.$message.error("只能上传 .paper 文件");
      }
      return isPaper;
    },

    // ✅ 上传成功回调
    handleSuccess(response) {
      if (response.code === 200) {
        this.fetchPapers(); // 刷新试卷列表
        this.$message.success(response.message || "导入成功");
      } else {
        this.$message.error(response.message || "导入失败");
      }
    },

    // ❌ 上传失败
    handleError(err) {
      this.$message.error("上传失败，请检查文件或权限");
    },
  },
};
</script>

<style lang="less" scoped>
@primary: #4361ee;
@primary-light: #a5b4fc;
@primary-lighter: #e0e7ff;
@secondary: #3a0ca3;
@success: #10b981;
@warning: #f59e0b;
@danger: #ef4444;
@gray-100: #f3f4f6;
@gray-200: #e5e7eb;
@gray-300: #d1d5db;
@gray-400: #9ca3af;
@gray-500: #6b7280;
@gray-600: #4b5563;
@gray-700: #374151;
@gray-800: #1f2937;
@gray-900: #111827;

@shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
@shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
@shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
@radius-sm: 0.375rem;
@radius-md: 0.5rem;
@radius-lg: 0.75rem;
@transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

.paper-list {
  flex: 1;
  padding: 2rem;
  background-color: @gray-100;

  .AIPaperGeneratorModal-class {
    display: flex;
    position: fixed;
    z-index: 1000;
    width: 100%;
    top: 0;
    left: 0;
    justify-content: center;
    height: 100vh;
    align-items: center;
    background: rgba(0, 0, 0, 0.4);
  }

  .panel-header {
    display: flex;
    // flex-direction: column;
    justify-content: space-between;
    gap: 1.5rem;
    margin-bottom: 2rem;
    height: 7%;
    .el-button--primary {
      background-color: #4361ee;
    }
    .header-content {
      .panel-title {
        margin: 0;
        font-size: 1.75rem;
        font-weight: 700;
        color: @gray-900;
        position: relative;
        padding-left: 1rem;

        &::before {
          content: "";
          position: absolute;
          left: 0;
          top: 0;
          bottom: 0;
          width: 4px;
          background: linear-gradient(to bottom, @primary, @secondary);
          border-radius: 2px;
        }
      }

      .panel-subtitle {
        margin: 0.5rem 0 0;
        font-size: 0.9375rem;
        color: @gray-500;
      }
    }

    .action-buttons {
      display: flex;
      gap: 1rem;
      align-items: center;

      .search-box {
        flex: 1;
        max-width: 400px;
        position: relative;
        transition: @transition;
        background: rgba(255, 255, 255, 0.9);
        border-radius: 12px;
        box-shadow: @shadow-sm;

        i {
          position: absolute;
          left: 1rem;
          top: 50%;
          transform: translateY(-50%);
          color: @gray-400;
          transition: @transition;
        }

        input {
          width: 100%;
          padding: 0.75rem 1rem 0.75rem 2.5rem;
          border: 1px solid @gray-300;
          border-radius: @radius-md;
          font-size: 0.9375rem;
          transition: @transition;
          background-color: transparent;

          &:focus {
            outline: none;
            border-color: @primary;
            box-shadow: 0 0 0 3px rgba(@primary, 0.1);

            + i {
              color: @primary;
            }
          }

          &::placeholder {
            color: @gray-400;
          }
        }
      }
    }
  }

  .loading-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 300px;
    gap: 1rem;

    .spinner {
      width: 40px;
      height: 40px;
      border: 4px solid rgba(@primary, 0.1);
      border-top-color: @primary;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }
    /* 底部提示信息 */
    .end-of-list {
      position: absolute;
      left: 50%;
      bottom: 0;
      transform: translateX(-50%);
      margin: 1rem 0;
    }
    p {
      margin: 0;
      color: @gray-600;
    }
  }
  .loading-indicator {
    text-align: center;
    justify-content: center;
    align-items: center;
  }
  .empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 400px;
    text-align: center;
    gap: 1rem;

    .empty-illustration {
      width: 80px;
      height: 80px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: @primary-light;
      font-size: 3rem;
      margin-bottom: 1rem;
    }

    h3 {
      margin: 0;
      color: @gray-800;
      font-size: 1.25rem;
    }

    p {
      margin: 0;
      color: @gray-500;
      max-width: 300px;
    }
  }

  .papers-grid {
    width: 100%;
    // border: 1px solid red;
    overflow: auto;
    height: 92%;
  }
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
</style>